/*
 * @Author: weidewei
 * @Date: 2025-06-09 09:10:12
 * @LastEditors: weidewei
 * @LastEditTime: 2025-06-09 09:11:57
 * @Description: 
 * @FilePath: \2025-front-face\手写题\手写深拷贝.js
 */
/* ● 使用JSON.stringify
  ○ 无法转换函数
  ○ 无法转换Map和Set
  ○ 无法转换循环引用 */

/* const obj = {
    num: 111,
    str: "222",
    fn: function () {
        console.log('fn执行了')
    },
    date: new Date(),
    reg: undefined,
    null: null
}  
const deepObj = JSON.stringify(obj)
console.log('obj',obj)
console.log("deepObj",JSON.parse(deepObj)) */

const obj1 = {
  a: 111,
  b: 222,
  c: {
    d: 3333,
  },
  e: undefined,
  f: function () {
    return {};
  },
};

// const obj2 = deepClone(obj1);
// obj2.a = "111"
// obj2.c.d = "999"
// obj2.g = obj2;
// console.log('obj1',obj1)
// console.log('obj2',obj2)

// 循环引用
obj1.g = obj1;
const res =  deepClone(obj1,new WeakMap())
console.log('res',res)

function deepClone(obj,hash=new WeakMap()) {
   if(obj === null || typeof obj !== 'object') {
    return obj
   } 
   if (hash.has(obj)) return hash.get(obj);
   let result = Array.isArray(obj) ? [] : {}
   hash.set(obj,result);
   for(let key in obj) {
    // 只判断自身上的属性，不拷贝原型上的东西
    if(obj.hasOwnProperty(key)) {
       result[key] = deepClone(obj[key],hash) 
    }
   }
   return result
} 

/**
 * 深拷贝
 * @param obj obj
 * @param map weakmap 为了避免循环引用、避免导致内存泄露的风险
 */
function deepClone(obj, map = new WeakMap()) {
  if (typeof obj !== "object" || obj == null) return obj;

  // 避免循环引用
  const objFromMap = map.get(obj);
  if (objFromMap) return objFromMap;

  let target = {};
  map.set(obj, target);

  // Map
  if (obj instanceof Map) {
    target = new Map();
    obj.forEach((v, k) => {
      const v1 = deepClone(v, map);
      const k1 = deepClone(k, map);
      target.set(k1, v1);
    });
  }

  // Set
  if (obj instanceof Set) {
    target = new Set();
    obj.forEach((v) => {
      const v1 = deepClone(v, map);
      target.add(v1);
    });
  }

  // Array
  if (obj instanceof Array) {
    target = obj.map((item) => deepClone(item, map));
  }

  // Object
  for (const key in obj) {
    const val = obj[key];
    const val1 = deepClone(val, map);
    target[key] = val1;
  }

  return target;
}
